#ifndef _MATERIAL_H_
#define _MATERIAL_H_

#include <assert.h>
#include "../d_Math/d_Math.h"

using namespace d_Math;

#include "ray.h"
#include "hit.h"
#include "image.h"

class Material {

public:

  // CONSTRUCTORS & DESTRUCTOR
  //Material(const Vec3f &d_color) { diffuseColor = d_color; }
  virtual ~Material() {}

  // ACCESSORS
  virtual d_Vec3f getDiffuseColor(d_Vec3f wc) const = 0; //const { return diffuseColor; }
  virtual d_Vec3f getReflectiveColor(d_Vec3f wc) const = 0; //const { return reflectiveColor; }
  virtual d_Vec3f getTransparentColor(d_Vec3f wc) const {return transparentColor;}
  virtual float getRefractionIndex() const {return refractionIndex;}
  virtual bool getIsTextured() const {return isTextured;}
  virtual Image *getTexture() const {return texture;}

  virtual d_Vec3f Shade(const Ray &ray, const Hit &hit, const d_Vec3f &dirToLight, const d_Vec3f &lightColor) const =0;

protected:

  // REPRESENTATION
  d_Vec3f diffuseColor;
  d_Vec3f reflectiveColor;
  d_Vec3f transparentColor;
  float refractionIndex;
  bool isTextured;
  Image *texture;
};

class PhongMaterial : public Material
{
public:
	PhongMaterial(const d_Vec3f &diffuseCol, const d_Vec3f &specularCol, float expon, const d_Vec3f &reflectiveCol, const d_Vec3f &transparentColor, float indexOfRefraction, d_Mat4f *trans , char* texture, char* bumpmap);
	d_Vec3f Shade(const Ray &ray, const Hit &hit, const d_Vec3f &dirToLight, const d_Vec3f &lightColor) const;
	d_Vec3f getSpecularColor() const {return specularColor;}
	d_Vec3f getDiffuseColor(d_Vec3f wc) const { return diffuseColor; }
	d_Vec3f getReflectiveColor(d_Vec3f wc) const { return reflectiveColor; }
	d_Vec3f getTransparentColor(d_Vec3f wc) const {return transparentColor;}
	
protected:
	Image *bumpmap;
	float exponent;
	d_Vec3f specularColor;
	d_Mat4f trans;
};

class CookTorranceMaterial : public Material
{
public:
	CookTorranceMaterial(const d_Vec3f &diffuseCol, const d_Vec3f &specularCol, float alpha, float roughness, const d_Vec3f &reflectiveCol, const d_Vec3f &transparentColor, d_Mat4f *trans);
	d_Vec3f Shade(const Ray &ray, const Hit &hit, const d_Vec3f &dirToLight, const d_Vec3f &lightColor) const;
	d_Vec3f getSpecularColor() const {return specularColor;}
	d_Vec3f getDiffuseColor(d_Vec3f wc) const { return diffuseColor; }
	d_Vec3f getReflectiveColor(d_Vec3f wc) const { return reflectiveColor; }
	
protected:
	float alpha, roughness;
	d_Vec3f specularColor;
	d_Mat4f trans;
};

class Checkerboard : public Material
{
public:
	Checkerboard(d_Mat4f *m, Material *mat1, Material *mat2);
	d_Vec3f Shade(const Ray &ray, const Hit &hit, const d_Vec3f &dirToLight, const d_Vec3f &lightColor) const;
	d_Vec3f getDiffuseColor(d_Vec3f wc) const { return diffuseColor; }
	d_Vec3f getReflectiveColor(d_Vec3f wc) const { return reflectiveColor; }
protected:
	d_Mat4f trans;
	Material *mat1;
	Material *mat2;
};

class Noise : public Material
{
public:
	Noise(d_Mat4f *m, Material *mat1, Material *mat2, int octaves);
	virtual d_Vec3f Shade(const Ray &ray, const Hit &hit, const d_Vec3f &dirToLight, const d_Vec3f &lightColor) const;
	d_Vec3f getDiffuseColor(d_Vec3f wc) const;
	d_Vec3f getReflectiveColor(d_Vec3f wc) const;
protected:
	d_Mat4f trans;
	Material *mat1;
	Material *mat2;
	int octaves;

};

class Marble : public Material
{
public:
	Marble(d_Mat4f *m, Material *mat1, Material *mat2, int octaves, float frequency, float amplitude);
	virtual d_Vec3f Shade(const Ray &ray, const Hit &hit, const d_Vec3f &dirToLight, const d_Vec3f &lightColor) const;
	d_Vec3f getDiffuseColor(d_Vec3f wc) const;
	d_Vec3f getReflectiveColor(d_Vec3f wc) const;
protected:
	d_Mat4f trans;
	Material *mat1;
	Material *mat2;
	int octaves;
	float frequency;
	float amplitude;

};

// ====================================================================
// ====================================================================

#endif

